/*
 * @(#)XfdmInputStyleDialog.java        1.0 2000/05/09
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package xfuzzy.xfdm.view;

import xfuzzy.util.*;
import xfuzzy.xfdm.view.listener.*;
import xfuzzy.xfdm.model.*;
import xfuzzy.xfdm.model.algorithm.*;
import xfuzzy.xfds.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;

/**
 * Di�logo de configuraci�n del estilo de las variables de entrada
 * 
 * @author Francisco Jos� Moreno Velo
 *
 */
public class XfdmInputStyleDialog extends JDialog implements IXfdmFrame {

	/**
	 * C�digo asociado a la clase serializable
	 */
	private static final long serialVersionUID = 95505666603015L;

	//----------------------------------------------------------------------------//
	//                            MIEMBROS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Ventana principal de la herramienta
	 */
	private Xfdm xfdm;
	
	/**
	 * Configuraci�n del proceso de extracci�n de conocimiento
	 */
	private XfdmConfig config;
	
	/**
	 * Lista de variables de entrada (atributos) extra�do del conjunto de datos
	 */
	private XfdsAttribute[] attr;
	
	/**
	 * Campos de texto para mostrar el nombre, n�mero de funciones de pertenencia y
	 * universo de discurso
	 */
	private XTextForm text[];
	
	/**
	 * Lista de selecci�n de la variable a mostrar
	 */
	private XList varlist;
	
	/**
	 * Conjunto de botones de estilo
	 */
	private JToggleButton toggle[];
	
	/**
	 * Botones de selecci�n del estilo de funciones de pertenencia
	 */
	private JRadioButton radio[];
	
	/**
	 * Estilo de las variables de entrada
	 */
	private XfdmInputStyle style[];
	
	/**
	 * Estilo seleccionado
	 */
	private XfdmInputStyle editing;

	//----------------------------------------------------------------------------//
	//                               CONSTRUCTOR                                  //
	//----------------------------------------------------------------------------//

	/**
	 * Constructor
	 */
	public XfdmInputStyleDialog(Xfdm xfdm){
		super(xfdm,"Xfdm",true);
		this.xfdm = xfdm;
		this.config = xfdm.getConfig();
		this.attr = config.getDataSet().getInputAttributes();
		build();
		getCopy();
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS P�BLICOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Actualiza la selecci�n de la variable a mostrar 
	 */
	public void actionListSelection() {
		int index = varlist.getSelectedIndex()+1;
		if(editing == style[index]) return;
		try { getStyle(); }
		catch(Exception ex) {
			for(int i=0; i<style.length; i++) if(editing == style[i]) varlist.setSelectedIndex(i); 
			setStyle(); 
			return; 
		}
		editing = style[index];
		setStyle();
	}
	
	/**
	 * Acci�n de cambiar el estilo a com�n
	 */
	public void actionSame() {
		if(editing != style[0]) { editing = style[0]; setStyle(); }
		varlist.setSelectedIndex(0);
		varlist.setEnabled(false);
	}

	/**
	 * Acci�n de cambiar el estilo a espec�fico	
	 */
	public void actionSpecific() {
		varlist.setEnabled(true);
	}

	/**
	 * Acci�n de almacenar los datos y cerrar la ventana
	 */
	public void actionSet() {
		try { getStyle(); } catch(Exception ex) { return; }
		if(radio[0].isSelected()) {
			config.setCommonInputStyle(new XfdmInputStyle(style[0]));
			config.setInputStyles(null);
		} else {
			XfdmInputStyle[] styles = new XfdmInputStyle[style.length-1];
			for(int i=1; i<style.length; i++) styles[i-1] = new XfdmInputStyle(style[i]);
			config.setInputStyles(styles);
			config.setCommonInputStyle(new XfdmInputStyle(style[0]));
		}
		xfdm.refresh();
		setVisible(false); 
	}

	/**
	 * Acci�n de cerrar la ventana
	 */
	public void actionCancel() {
		setVisible(false); 
	}

	/**
	 * Acci�n de cerrar la ventana
	 */
	public void close() {
		setVisible(false);
	}
	
	//----------------------------------------------------------------------------//
	//                             M�TODOS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	//----------------------------------------------------------------------------//
	// M�todos de descripci�n de la interfaz gr�fica                              //
	//----------------------------------------------------------------------------//

	/**
	 * Generaci�n de la ventana
	 */
	private void build() {
		ChangeListener changeListener = new XfdmInputChangeListener(this);
		ActionListener actionListener = new XfdmInputActionListener(this);
		String lb[] = {"Set", "Cancel"};
		XCommandForm form = new XCommandForm(lb,lb,actionListener);
		form.setCommandWidth(150);
		form.block();

		text = new XTextForm[4];
		text[0] = new XTextForm("Variable name"); text[0].setEditable(false);
		text[1] = new XTextForm("Number of MFs");
		text[2] = new XTextForm("Minimum"); text[2].setEditable(false);
		text[3] = new XTextForm("Maximum"); text[3].setEditable(false);
		XTextForm.setWidth(text);

		toggle = new JToggleButton[6];
		JPanel stbox = new JPanel();
		stbox.setLayout(new GridLayout(3,2));
		ButtonGroup stbg = new ButtonGroup();
		ImageIcon icon[] = {
				XfdmIcons.triangles,  XfdmIcons.triangles,
				XfdmIcons.sh_triangles,  XfdmIcons.sh_triangles,
				XfdmIcons.gaussians,  XfdmIcons.splines };

		String togglelabel[] = {
				"Free triangles", "Triangular family",
				"Free shouldered triangles", "Shouldered-triangular family",
				"Free gaussians", "B-splines family" };

		for(int i=0; i<toggle.length; i++) {
			toggle[i] = new JToggleButton(togglelabel[i],icon[i]);
			toggle[i].setFont(XConstants.textfont);
			toggle[i].setVerticalTextPosition(JToggleButton.BOTTOM);
			toggle[i].setHorizontalTextPosition(JToggleButton.CENTER);
			toggle[i].setBorder(BorderFactory.createRaisedBevelBorder());
			toggle[i].setFocusPainted(false);
			toggle[i].setContentAreaFilled(false);
			toggle[i].addChangeListener(changeListener);
			stbg.add(toggle[i]);
			stbox.add(toggle[i]);
		}

		Box rbox = new Box(BoxLayout.Y_AXIS);
		rbox.add(text[0]);
		rbox.add(text[1]);
		rbox.add(text[2]);
		rbox.add(text[3]);
		rbox.add(Box.createVerticalStrut(5));
		rbox.add(new XLabel("Style"));
		rbox.add(stbox);

		radio = new JRadioButton[2];
		radio[0] = new JRadioButton("same for all variables");
		radio[1] = new JRadioButton("individually for each variable");
		radio[0].addActionListener(actionListener);
		radio[1].addActionListener(actionListener);
		radio[0].setActionCommand("Same");
		radio[1].setActionCommand("Specific");

		JPanel rpanel = new JPanel();
		rpanel.setLayout(new GridLayout(2,1));
		rpanel.add(radio[0]);
		rpanel.add(radio[1]);

		ButtonGroup rbg = new ButtonGroup();
		rbg.add(radio[0]);
		rbg.add(radio[1]);
		varlist = new XList("Input variables");
		varlist.setPreferredWidth(130);
		varlist.addListSelectionListener(new XfdmInputListSelectionListener(this));

		Box lbox = new Box(BoxLayout.Y_AXIS);
		lbox.add(rpanel);
		lbox.add(Box.createVerticalStrut(5));
		lbox.add(varlist);

		Box box = new Box(BoxLayout.X_AXIS);
		box.add(Box.createHorizontalStrut(5));
		box.add(lbox);
		box.add(Box.createHorizontalStrut(5));
		box.add(rbox);
		box.add(Box.createHorizontalStrut(5));

		Container content = getContentPane();
		content.setLayout(new BoxLayout(content,BoxLayout.Y_AXIS));
		content.add(new XLabel("Input Style"));
		content.add(Box.createVerticalStrut(5));
		content.add(box);
		content.add(Box.createVerticalStrut(5));
		content.add(form);

		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		addWindowListener(new XfdmWindowListener(this));
		pack();
		setLocation();
	}

	/**
	 * Coloca la ventana en la pantalla
	 */
	private void setLocation() {
		Dimension frame = getSize();
		Dimension screen = getToolkit().getScreenSize();
		setLocation((screen.width - frame.width)/2,(screen.height - frame.height)/2);
	}

	/**
	 * Genera la copia de trabajo
	 */
	private void getCopy() {
		int numinputs = attr.length;
		style = new XfdmInputStyle[numinputs+1];
		
		if(config.getCommonInputStyle() == null) style[0] = new XfdmInputStyle();
		else style[0] = new XfdmInputStyle(config.getCommonInputStyle());
		
		XfdmInputStyle[] istyle = config.getInputStyles();
		if(istyle == null || istyle.length == 0) {
			for(int i=0; i<numinputs; i++) {
				style[i+1] = new XfdmInputStyle(i);
			}
		} else {
			for(int i=0; i<numinputs; i++) {
				if(i<istyle.length) {
					style[i+1] = new XfdmInputStyle(istyle[i]);
				} else {
					style[i+1] = new XfdmInputStyle(style[0]);
					style[i+1].setIndex(i);
				}
			}
		}

		varlist.setListData(attr);
		if(istyle != null && istyle.length > 0) {
			radio[1].setSelected(true);
			varlist.setEnabled(true);
		} else {
			radio[0].setSelected(true);
			varlist.setEnabled(false);
		}
		this.editing = style[0];
		setStyle();
	}

	/**
	 * Actualiza los datos de estilo con la variable seleccionada
	 */
	private void setStyle() {
		int index = editing.getIndex();
		if(index < 0 ) {
			text[0].setText("Common");
			text[1].setText(""+editing.getNumberOfMFs());
			toggle[editing.getStyle()].setSelected(true);
			text[2].setText("");
			text[3].setText("");
		}
		else {
			text[0].setText(attr[index].getName());
			text[1].setText(""+editing.getNumberOfMFs());
			toggle[editing.getStyle()].setSelected(true);
			text[2].setText(""+attr[index].getUniverse().min());
			text[3].setText(""+attr[index].getUniverse().max());
		}
		setConstraints();
	}

	/**
	 * Considera las restricciones que imponen los algoritmos
	 */
	private void setConstraints() {
		XfdmAlgorithm algorithm = config.getAlgorithm();
		if(algorithm == null) return;
		if(algorithm instanceof XfdmIncGrid) {
			text[1].setText("");
			text[1].setEditable(false);
			int st = editing.getStyle();
			if(st != XfdmInputStyle.FREE_TRIANGLES && st != XfdmInputStyle.TRIANGULAR_FAMILY) {
				st = XfdmInputStyle.FREE_TRIANGLES;
				editing.setStyle(st);
			}
			toggle[st].setSelected(true);
			toggle[XfdmInputStyle.FREE_SH_TRIANGLES].setEnabled(false);
			toggle[XfdmInputStyle.SH_TRIANGULAR_FAMILY].setEnabled(false);
			toggle[XfdmInputStyle.FREE_GAUSSIANS].setEnabled(false);
			toggle[XfdmInputStyle.BSPLINES_FAMILY].setEnabled(false);
		} 
		if(algorithm instanceof XfdmIncClustering || algorithm instanceof XfdmFixedClustering) {
			text[1].setText("");
			text[1].setEditable(false);
			editing.setStyle(XfdmInputStyle.FREE_GAUSSIANS);
			toggle[XfdmInputStyle.FREE_GAUSSIANS].setSelected(true);
			for(int i=0; i<toggle.length; i++) toggle[i].setEnabled(false);
		} 
	}

	/**
	 * Actualiza la variable seleccionada con los datos de estilo
	 */
	private void getStyle() throws Exception {
		int mfs = 3;
		XfdmAlgorithm algorithm = config.getAlgorithm();
		if(algorithm != null && algorithm.needInputMemFuncs()) mfs = getIntegerValue();
		if(mfs == -1) throw new Exception();
		editing.setNumberOfMFs(mfs);
		for(int i=0;i<toggle.length;i++) if(toggle[i].isSelected()) editing.setStyle(i);
	}

	/**
	 * Detecta posibles errores en el numero de MFs
	 */
	private int getIntegerValue() {
		int val = -1;
		try { val = Integer.parseInt(text[1].getText()); }
		catch(NumberFormatException ex) {
			text[1].setText("");
			XDialog.showMessage(text[1],"Not a numeric value");
			return -1;
		}
		if(val <= 0) {
			text[1].setText("");
			XDialog.showMessage(text[1],"Not a valid value");
			return -1;
		}
		return val;
	}

}


